home *** CD-ROM | disk | FTP | other *** search
- PAGE 60,132
- TITLE ISRESDNT.ASM
- PAGE
- ;-----------------------------------------------------------------------------
- ; SUMMARY
- ;-----------------------------------------------------------------------------
-
- ; Near Procedure is_resident.
- ; Find out if a copy of this program is resident.
-
- ; Input:
- ; SI = OFFSET of the signature (see below)
- ; DI = OFFSET of test string (see below)
- ; AX = number of characters in test string (see below)
- ; DS = DS for calling program*
- ; ES = PSP segment address for the calling program
- ; *The DOS loader sets DS and ES properly in the case of COM
- ; files. It sets ES properly in the case of EXE files, and the
- ; calling program must set DS before calling this procedure.
-
- ; Output:
- ; AX indicates the result of the procedure:
- ; = 0 if it does not find a copy already resident
- ; = 1 if it finds a copy already resident
- ; = -1 if the DOS major version is not legal
- ; | = -2 if there is a memory allocation error
- ; CF is set if a copy of this program is resident or if the
- ; DOS version is not legal
- ; DS = DS for the first copy of this program in memory. Note
- ; that if no earlier copy is resident, it is DS of the
- ; calling program.
- ; ES = DS for the calling program.
-
- ; This procedure examines memory which could contain a copy
- ; of itself for a signature, which is a word which is ideally quite
- ; rare in other contexts. If it finds a match, it then checks
- ; whether the proper memory also matches a test string, which should
- ; positively identify a copy. If it finds a match, it sets DS to
- ; the DS value for the copy and sets the carry flag. Otherwise, it
- ; sets DS to the DS value for this copy and unsets the carry flag.
- ; If you haven't changed any of the ASSUME's, a memory reference
- ; with no segment override will refer to the first copy of the pro-
- ; gram, and a memory reference with an ES segment override will refer
- ; to this copy of the program.
-
- ; A good value for the signature would be a word made up of
- ; the first two letters of the program name, OR'ed with 8080H to
- ; avoid all ASCII codes. The procedure replaces the first two
- ; characters of the test string with the signature to distinguish
- ; between a run copy of the program and a tramp copy. As a result,
- ; the first word of the test string should be different than the
- ; signature. A DW 0 is as good as anything. The rest of the test
- ; string could be the program name itself.
-
- ; The segment name COMSEG matches COMSKEL.ASM. If the calling
- ; program has a different segment name, change it to match. The
- ; calling program should contain:
- ; EXTRN is_resident:NEAR
- ; inside its COMSKEL (or equivalent) segment.
- ;
-
- ; | Chris Dunford sent me the following information on 6/16/86:
- ; | "For each block of allocated memory, DOS maintains a 16-byte
- ; | (one paragraph) block header. The header is located in the
- ; | paragraph immediately preceding the allocated block. ...
- ; | The form of the header is as follows:
- ; | OFFSET TYPE CONTENTS
- ; | 0 Byte 'Z' = this is the last block in the chain
- ; | 'M' = this is not the last block
- ; | Anything else means that the memory allocation
- ; | chain has been destroyed (this is the source of
- ; | DOS's "Memory allocation error" message).
- ; |
- ; | 1 Word Segment address of Program Segment Prefix of the
- ; | program that 'owns' this block. Zero here
- ; | indicates that the block is unallocated (free).
- ; |
- ; | 3 Word Size of block in paragraphs (does not include
- ; | size of header).
- ; |
- ; | ...
- ; |
- ; | ... the address of the first header block by using the
- ; | undocumented DOS function 52H. On return, the word at ES:[BX-2]
- ; | contains the segment at which you should find the first header."
-
- ; | Since DOS function 52H is undocumented, this procedure may
- ; | not work with Version 1.? or with Version 4.? or later. I have
- ; | called these values MIN_DOS and MAX_DOS. If it does work, change
- ; | one or both of them.
- ; Author : Lew Paper
- ; Date written: 6/10/86
- ; Revisions :
- ; 6/28/86 Revise to use DOS 2 and 3 memory allocation
- ; block information.
-
- ;-----------------------------------------------------------------------------
- ; INITIAL DIRECTIVES
- ;-----------------------------------------------------------------------------
-
- MIN_DOS EQU 2
- MAX_DOS EQU 3
-
- ; Synonyms for variables saved on the stack
- length_test_string EQU [BP+0] ; Length of test string
- old_DS EQU [BP+2] ; DS from calling program
- original_stack_junk EQU 4 ; Number of bytes on stack for
- ; variables which will not be
- ; restored at all exits.
-
- doscall MACRO
- INT 21h ; call MS-DOS function
- ENDM ; doscall
-
- COMSEG SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:COMSEG,DS:COMSEG,ES:COMSEG,SS:COMSEG
-
- ;-----------------------------------------------------------------------------
- PUBLIC is_resident
- is_resident PROC NEAR
- PUSH BX ; Save uninitialized registers
- PUSH CX
- PUSH DX
- PUSH BP
- PUSH ES
-
- PUSH DS ; Synonym old_DS
- PUSH AX ; Synonym length_test_string
- MOV BP,SP ; Establish variables on stack
-
- MOV AH,30H ; get DOS version
- doscall
- CMP AL,MIN_DOS ; Is major version too early?
- JL wrong_DOS ; Yes
- CMP AL,MAX_DOS ; Is major version too late?
- JLE DOS_ok ; No
-
- wrong_DOS:
- ADD SP,original_stack_junk
- ; Clear unneeded words from stack
- MOV AX,-1 ; Error indicator
- STC ; Set carry flag
- JMP is_resident_exit
-
- DOS_ok:
-
- ; Call function 52 first, because it is undocumented, so may have
- ; some side effects.
- PUSH DS ; DS for calling program
- PUSH ES ; Segment of PSP for calling program
- MOV AH,52H ; Find segment of first block header
- doscall
- MOV AX,ES:[BX-2] ; Segment of first block header
- POP ES ; Restore segment registers
- POP DS ;
- PUSH AX ; Segment of first block header
-
- MOV DX,DS ; DS for calling program
- MOV CX,ES ; Segment of PSP, which is the first
- ; paragraph which DOS allocates for
- ; a program
- DEC CX ; Segment of block header for calling
- ; program
- SUB DX,CX ; Number of paragraphs from block
- ; header to DS
-
- MOV AX,WORD PTR [SI] ; Signature => AX
- MOV WORD PTR [DI],AX ; Signature to start of test string.
- ; This distinguishes a copy which has
- ; been run from a tramp copy in RAM.
-
- POP ES ; Segment of first block header
-
- check_last_block:
- CMP BYTE PTR ES:[0],'M' ; Is there another block in the chain?
- JNZ check_destruction ; No
- TEST ES:[1],0FFFFH ; Is the current block unallocated
- JZ get_next_block ; Yes, so don't check it
- CMP DX,WORD PTR ES:[3] ; Is the current block big enough to
- ; match?
- JG get_next_block ; No
- MOV BX,ES ; Segment of block header
- CMP BX,CX ; Segment of block header for calling
- ; program
- JZ get_next_block ; Don't compare a block to itself
- ADD BX,DX ; Number of paragraphs from block
- ; header to DS
- MOV DS,BX ; Set new DS
- CMP AX,WORD PTR [SI] ; Does this segment contain the
- ; signature?
- JE signatures_match ; Yes. Compare test strings
- get_next_block:
- MOV BX,ES ; Current block header
- INC BX ; Current block segment
- ADD BX,ES:[3] ; Number of paragraphs in current
- ; block
- MOV ES,BX ; Next block header
- JMP SHORT check_last_block ; And check again
-
- signatures_match:
- PUSH ES ; Current block header
- PUSH CX ; Segment of block header for calling
- ; program
- PUSH SI ; OFFSET of signature
- PUSH DI ; OFFSET of test string
- MOV SI,DI ; OFFSET of test string => SI
- MOV ES,old_DS ; DS of calling program
- MOV CX,length_test_string ; Number of characters in test string
- REPE CMPSB ; Are the test strings equal?
- POP DI ; Restore OFFSET of test string
- POP SI ; Restore OFFSET of signature
- POP CX ; Restore segment of block header for
- ; calling program
- POP ES ; Restore current block header
- JZ already_installed ; Equal test strings
- JMP SHORT get_next_block
- ; Check again if still possible
- check_destruction:
- CMP BYTE PTR ES:[0],'Z' ; Is this the last block in the chain?
- JZ first_copy ; Yes
- MOV AX,-2 ; Memory allocation error indicator
- ADD SP,original_stack_junk
- ; Move stack pointer up
- STC ; Set carry flag
- JMP SHORT is_resident_exit
-
- ; No earlier resident copy.
- first_copy:
- MOV DS,old_DS ; DS of calling program
- XOR AX,AX ; Show no copy is resident
- ADD SP,original_stack_junk
- ; Move stack pointer up
- CLC ; Clear carry flag
- JMP SHORT is_resident_exit
-
- already_installed:
- MOV AX,1 ; Show a copy is resident
- ADD SP,original_stack_junk
- ; Move stack pointer up
- STC ; Set carry flag
-
- is_resident_exit:
- POP ES ; Restore uninitialized registers
- POP BP
- POP DX
- POP CX
- POP BX
- RET
-
- is_resident ENDP
-
- ;-----------------------------------------------------------------------------
- ; OVERALL END
- ;-----------------------------------------------------------------------------
- COMSEG ENDS
- END
-
-